use std::sync::mpsc::{Sender, Receiver};
use specs::{System, Entities, ReadStorage};
use specs::world::Index;
use crate::res::position_storage::Position;
use crate::res::overlord_storage::Overlord;

#[derive(Clone)]
pub struct QuerySelectedPositionStreamMessage
{
    target: Vec<Index>,
    to: Sender<Vec<(Index, Position)>>,
    who: Index,
}

impl QuerySelectedPositionStreamMessage
{
    pub fn new(target: Vec<Index>, to: Sender<Vec<(Index, Position)>>, who: Index) -> Self {
        QuerySelectedPositionStreamMessage {
            target,
            to,
            who,
        }
    }
}

pub struct QuerySelectedPositionStreamSystem
{
    rc: Receiver<QuerySelectedPositionStreamMessage>,
    streams: Vec<QuerySelectedPositionStreamMessage>,
}

impl QuerySelectedPositionStreamSystem
{
    pub fn new(rc: Receiver<QuerySelectedPositionStreamMessage>) -> Self {
        QuerySelectedPositionStreamSystem {
            rc,
            streams: Vec::new(),
        }
    }
}

impl<'a> System<'a> for QuerySelectedPositionStreamSystem
{
    type SystemData = (
        Entities<'a>,
        ReadStorage<'a, Position>,
        ReadStorage<'a, Overlord>,
    );

    fn run(&mut self, data: Self::SystemData) {
        let (entities, position_storage, overlord_storage) = data;

        if let Ok(report) = self.rc.try_recv() {
            self.streams.push(report);
        }

        let mut to_remove = Vec::new();

        for (i, stream) in self.streams.iter().enumerate() {
            let mut result = Vec::new();

            for entity_id in stream.target.iter() {
                let entity = entities.entity(entity_id.clone());

                if let Some(overlord) = overlord_storage.get(entity) {
                    if overlord.0 == stream.who {
                        if let Some(position) = position_storage.get(entity) {
                            result.push((entity_id.clone(), position.clone()));
                        }
                    }
                }
            }
            
            if let Err(_) = stream.to.send(result.clone()) {
                to_remove.push(i);
            }
        }

        for index in to_remove.iter() {
            self.streams.remove(index.clone());
        }
    }
}
